#include "pch.h"
#include "Utility.h"

namespace Util
{

void FormatFilePath(std::wstring& strFilePath)
{
	if (strFilePath.empty())
		return;

	for (auto& ch : strFilePath)
	{
		if (ch == '/')
			ch = '\\';
	}

	if (strFilePath.back() != '\\')
		strFilePath += '\\';
}

bool EnumDirectory(LPCWSTR lpFileName, const std::function<bool(FIND_DATA&&)>& fnCallback)
{
	if (!lpFileName || !fnCallback)
		return false;

	WIN32_FIND_DATAW findData;
	HANDLE hFind = FindFirstFileExW(lpFileName, FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY);

	if (hFind == INVALID_HANDLE_VALUE)
		return false;

	bool bRet = true;

	do
	{
		if (findData.cFileName[0] == '.' && (findData.cFileName[1] == 0 || findData.cFileName[1] == '.' && findData.cFileName[2] == 0))
			continue;

		if (!fnCallback(std::move(findData)))
		{
			bRet = false;
			break;
		}
	} while (FindNextFileW(hFind, &findData));

	FindClose(hFind);
	return bRet;
}

bool DoDeleteDirectory(std::wstring& strFilePath)
{
	const size_t nPathLen = strFilePath.size();
	strFilePath += '*';

	std::vector<std::wstring> vecDirectories;

	bool bRet = EnumDirectory(strFilePath.c_str(), [&](FIND_DATA&& findData)
	{
		strFilePath.resize(nPathLen);
		strFilePath += findData.cFileName;

		if (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
			SetFileAttributesW(strFilePath.c_str(), FILE_ATTRIBUTE_NORMAL);

		if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			vecDirectories.emplace_back(findData.cFileName);
		else
			DeleteFileW(strFilePath.c_str());

		return true;
	});

	for (const auto& strDirName : vecDirectories)
	{
		strFilePath.resize(nPathLen);
		strFilePath += strDirName;
		strFilePath += '\\';

		if (!DoDeleteDirectory(strFilePath))
			bRet = false;
	}

	strFilePath.resize(nPathLen);

	if (!RemoveDirectoryW(strFilePath.c_str()))
		bRet = false;

	return bRet;
}

bool DeleteDirectory(LPCWSTR lpPathName)
{
	if (!lpPathName || *lpPathName == 0)
		return false;

	std::wstring strPathName;
	strPathName.reserve(MAX_PATH);
	strPathName = lpPathName;
	FormatFilePath(strPathName);

	return DoDeleteDirectory(strPathName);
}

bool GetConfigFile(std::wstring& strFileName)
{
	// GaojieDrive.ini
	strFileName.resize(MAX_PATH);
	size_t nSize = GetModuleFileNameW(NULL, (LPWSTR)strFileName.c_str(), MAX_PATH);

	if (nSize == 0 || nSize == MAX_PATH)
		return false;

	strFileName.resize(nSize);

#ifdef _DEBUG
	if (auto nPathLen = strFileName.find_last_of('\\'); nPathLen != std::wstring::npos)
	{
		strFileName.resize(nPathLen);

		if (nPathLen >= 6 && _wcsicmp(strFileName.c_str() + nPathLen - 6, L"\\Debug") == 0)
		{
			strFileName.resize(nPathLen -= 6);

			if (nPathLen >= 4 && _wcsicmp(strFileName.c_str() + nPathLen - 4, L"\\x64") == 0)
				strFileName.resize(nPathLen -= 4);
		}
	}

	strFileName += L"\\GaojieDrive.ini";
#else
	if (nSize < 15 || _wcsicmp(strFileName.c_str() + nSize - 15, L"GaojieDrive.exe") != 0)
		return false;

	strFileName.resize(nSize - 3);
	strFileName += L"ini";
#endif

	return true;
}

}	// namespace Util
